/*******************************************************************************
* @file    fins_debug.h
* @author  Fins
* @brief   
* @time    2020-11-15 11:08:46 Sunday
* @codeing UTF-8
* @license
*     Copyright 2020 Fins
*
*     Licensed under the Apache License, Version 2.0 (the "License");
*     you may not use this file except in compliance with the License.
*     You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*     Unless required by applicable law or agreed to in writing, software
*     distributed under the License is distributed on an "AS IS" BASIS,
*     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*     See the License for the specific language governing permissions and
*     limitations under the License.
* @verbatim
================================================================================
                        ##### xxxxxxxxxxxxxxxxxxxxxxx #####
================================================================================
* @endverbatim
* @attention
*******************************************************************************/



/** Prevent recursive inclusion */
#ifndef __FINS_DEBUG_H
#define __FINS_DEBUG_H

/** C++ compatible */
#ifdef __cplusplus
 extern "C" {
#endif /** __cplusplus */

/* Includes start *************************************************************/
/*     Lib files ****************************** */
#include <stdio.h>
/*     User files ***************************** */
#include "fins_define.h"
#include "../fins_framework_config.h"

/* Includes end ***************************************************************/
#if USE_FINS_DEBUG == 1
/* Exported define start ******************************************************/

/*************************************************
 * @brief Debug level
 ************************************************/
#define FDB_UNUSE              0
#define FDB_ASSRET_LV          1
#define FDB_ERROR_LV           2
#define FDB_WARNING_LV         3
#define FDB_INFORMATION_LV     4

/*************************************************
 * @brief Debug level
 *     Valid value: 0~4
 *         FDB_UNUSE : No debug
 *         FDB_ASSRET_LV : Use level =< FDB_ASSRET_LV
 *         FDB_ERROR_LV : Use level =< FDB_ERROR_LV
 *         FDB_WARNING_LV : Use level =< FDB_WARNING_LV
 *         FDB_INFORMATION_LV : Use all
 ************************************************/
#ifndef FDB_LEVEL
    #define FDB_LEVEL FDB_INFORMATION_LV
#endif

/*************************************************
 * @brief Debug tag
 ************************************************/
#ifndef FDB_TAG
    #define FDB_TAG   "NoTag"
#endif

/*************************************************
 * @brief Interface function
 ************************************************/
#define FdbPrintf                printf 

/*************************************************
 * @brief RGB color
 ************************************************/
#if FINS_DEBUG_OUT_ENABLE_RGB == 1
    #define __FDB_CLR_DEF                         "0"
    #define __FDB_CLR_GREEN                       "32"
    #define __FDB_CLR_YELLOW                      "33"
    #define __FDB_CLR_RED                         "31"
    #define __FDB_CLR_FWHITE_BRED                 "37;41"

    #define __FDB_OUT_SET(pram)    \
        FdbPrintf("\033[%sm",pram)
#else 
    #define __FDB_OUT_SET(pram)
#endif /* FINS_DEBUG_OUT_ENABLE_RGB == 1 */

/*************************************************
 * @brief Log output (internal define)
 ************************************************/
#define __FDB_LOG(level,fmt, ...)                                              \
    do                                                                         \
    {                                                                          \
        FdbPrintf("[%s@%d] %s: ", level, __LINE__, FDB_TAG);                   \
        FdbPrintf(fmt, ##__VA_ARGS__);                                         \
        FdbPrintf("\r\n");                                                     \
    } while (0)

/*************************************************
 * @brief Assert faile process (internal define)
 ************************************************/
#define __FDB_ASSERT_FAILED(exprStr, fmt, ...)                                 \
    do                                                                         \
    {                                                                          \
        FdbPrintf("[AF@%d] %s( %s ): ", __LINE__, FDB_TAG, exprStr);           \
        FdbPrintf(fmt, ##__VA_ARGS__);                                         \
        FdbPrintf("\r\n");                                                     \
        while (1);                                                             \
    } while (0)


/*************************************************
 * @brief Information
 ************************************************/
#if (FDB_LEVEL >= FDB_INFORMATION_LV)
    #define FDB_I(fmt, ...)                                                    \
        do                                                                     \
        {                                                                      \
            __FDB_OUT_SET(__FDB_CLR_GREEN);                                    \
            __FDB_LOG("I",fmt,##__VA_ARGS__);                                  \
            __FDB_OUT_SET(__FDB_CLR_DEF);                                      \
        } while (0)
    #define FDB_I_HEX(width, buff, size)                                       \
        do                                                                     \
        {                                                                      \
            __FDB_OUT_SET(__FDB_CLR_GREEN);                                    \
            __FdbHex(                                                          \
                FDB_TAG, #buff, width, buff, size,                             \
                __FILE__, __func__, __LINE__);                                 \
            __FDB_OUT_SET(__FDB_CLR_DEF);                                    \
        } while (0)
#else
    #define FDB_I(fmt, ...)
    #define FDB_I_HEX(width, buff, size)
#endif

/*************************************************
 * @brief Warning
 ************************************************/
#if (FDB_LEVEL >= FDB_WARNING_LV)
    #define FDB_W(fmt, ...)                                                    \
        do                                                                     \
        {                                                                      \
            __FDB_OUT_SET(__FDB_CLR_YELLOW);                                   \
            __FDB_LOG("W",fmt,##__VA_ARGS__);                                  \
            __FDB_OUT_SET(__FDB_CLR_DEF);                                      \
        } while (0)
#else
    #define FDB_W(...)
#endif

/*************************************************
 * @brief Error
 ************************************************/
#if (FDB_LEVEL >= FDB_ERROR_LV)
    #define FDB_E(fmt, ...)                                                    \
        do                                                                     \
        {                                                                      \
            __FDB_OUT_SET(__FDB_CLR_RED);                                      \
            __FDB_LOG("E",fmt,##__VA_ARGS__);                                  \
            __FDB_OUT_SET(__FDB_CLR_DEF);                                      \
        } while (0)
#else
    #define FDB_E(...)
#endif

/*************************************************
 * @brief Assert
 ************************************************/
#if (FDB_LEVEL > FDB_ASSRET_LV)
    #define FDB_ASSERT(expr)                                                   \
        do                                                                     \
        {                                                                      \
            if(expr);                                                          \
            else                                                               \
            {                                                                  \
                __FDB_OUT_SET(__FDB_CLR_FWHITE_BRED);                          \
                __FDB_ASSERT_FAILED(#expr,"");                                 \
                __FDB_OUT_SET(__FDB_CLR_DEF);                                  \
            }                                                                  \
        } while (0)

    #define FDB_ASSERT_MSG(expr, fmt, ...)                                     \
        do                                                                     \
        {                                                                      \
            if(expr);                                                          \
            else                                                               \
            {                                                                  \
                __FDB_OUT_SET(__FDB_CLR_FWHITE_BRED);                          \
                __FDB_ASSERT_FAILED(#expr,fmt,##__VA_ARGS__);                  \
                __FDB_OUT_SET(__FDB_CLR_DEF);                                  \
            }                                                                  \
        } while (0)
#else
    #define FDB_ASSERT(expr)                   ((void)0)
    #define FDB_ASSERT_MSG(...)                ((void)0)
#endif

/* Exported define end ********************************************************/

/* Exported typedef start *****************************************************/





/* Exported typedef end *******************************************************/

/* Exported variable start ****************************************************/





/* Exported variable end ******************************************************/

/* Exported function start ****************************************************/

extern void __FdbHex(
    const fuint8* tag, 
    const fuint8* name, 
    fuint8 width, 
    const fuint8* buff,
    fuint32 buffsize,
    const fuint8* file, 
    const fuint8* func, 
    fuint32 line);



/* Exported function end ******************************************************/

#endif /** USE_FINS_DEBUG */

/** C++ compatible */
#ifdef __cplusplus
}
#endif /** __cplusplus */

#endif /** __FINS_DEBUG_H */

////////////////////////////////- END OF FILE  -////////////////////////////////
